package com.bloom.controller;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import org.apache.commons.lang.RandomStringUtils;

import com.bloom.dao.StaticDataDao;
import com.bloom.dao.TravelServiceDao;
import com.bloom.entity.ServiceProvider;
import com.bloom.entity.ServiceReceiver;
import com.bloom.entity.UserTravelDetails;
import com.bloom.model.ServiceInfo;
import com.bloom.model.ServiceInfo.ServiceType;
import com.bloom.model.ServiceInfo.UserType;
import com.bloom.util.validation.UserCheck;
import com.bloom.util.validation.ServiceCheck;
import com.bloom.model.TravelInfo;
import com.bloom.entity.User;
import com.bloom.util.EnumEditor;
import com.bloom.util.MailUtil;
import com.bloom.exception.UserExistsException;

@Controller
@SessionAttributes("service")
public class FlowController {

	@Autowired
	private StaticDataDao staticDataDao;

	@Autowired
	private TravelServiceDao travelServiceDao;

	@RequestMapping(value = "", method = RequestMethod.GET)
	public String getHomePage(Model model) {
		model.addAttribute("service", new ServiceInfo());
		return "index";
	}

	@RequestMapping(value = "submitUserType", method = RequestMethod.POST)
	public String submitUserType(
			@ModelAttribute("service") @Validated(UserCheck.class) ServiceInfo serviceInfo,
			BindingResult result, Model model) {
		String nextView = "index";

		if (result.hasErrors()) {
			return nextView;
		}

		nextView = getServicePage(serviceInfo.getUserType());

		model.addAttribute("service", serviceInfo);
		return nextView;
	}

	private String getServicePage(UserType userType) {
		String nextView = null;
		if (userType == UserType.SEEKER)
			nextView = "page2";
		else if (userType == UserType.HELPER)
			nextView = "ServiceProviderServicesPage";
		return nextView;
	}

	@RequestMapping(value = "submitServiceType", method = RequestMethod.POST)
	public String submitServiceType(
			@ModelAttribute("service") @Validated(ServiceCheck.class) ServiceInfo serviceInfo,
			BindingResult result, Model model) {
		if (result.hasErrors()) {
			return getServicePage(serviceInfo.getUserType());
		}
		String nextView = "page3";
		model.addAttribute("modeOpts", staticDataDao.getTransportModes());
		model.addAttribute("cntryList", staticDataDao.getCountryList());
		model.addAttribute("cityList", staticDataDao.getCityList());

		model.addAttribute("travelForm", new TravelInfo());
		return nextView;
	}

	@RequestMapping(value = "submitTravelInfo", method = RequestMethod.POST)
	public String submitTravelInfo(
			@ModelAttribute("service") ServiceInfo serviceInfo,
			@ModelAttribute TravelInfo travelInfo, Model model,
			Principal principal) {
		String nextView = "page4";
		UserTravelDetails travelDetails = travelServiceDao
				.loadTravelDetails(travelInfo);
		if (travelDetails == null) {
			travelServiceDao.saveTravelDetails(travelInfo);
		}
		travelDetails = travelServiceDao.loadTravelDetails(travelInfo);

		List<?> serviceProviders = Collections.EMPTY_LIST;
		if (travelDetails != null) {
			if (principal != null && principal.getName() != null) {
				return "redirect:results/" + travelDetails.getId();
			}

			if (serviceInfo.getUserType() == UserType.HELPER) {
				serviceProviders = travelServiceDao
						.loadServiceReceivers(travelDetails.getId());
			} else {// seeker

				serviceProviders = travelServiceDao
						.loadServiceProviders(travelDetails.getId());

			}
		}

		model.addAttribute("noOfResults", serviceProviders.size());
		model.addAttribute("travelId", travelDetails.getId());

		return nextView;
	}

	@RequestMapping(value = "results/{tid}", method = RequestMethod.GET)
	public String showResults(
			@ModelAttribute("service") ServiceInfo serviceInfo,
			@PathVariable("tid") int travelId, Model model, Principal principal)
			throws Exception {
		if (principal == null || principal.getName() == null) {
			throw new Exception();
		}
		String userId = principal.getName();

		List<User> users = new ArrayList<User>();
		if (serviceInfo.getUserType() == UserType.HELPER) {
			travelServiceDao.saveServiceProvider(travelId, userId);
			List<ServiceReceiver> serviceReceivers = travelServiceDao
					.loadServiceReceivers(travelId);
			for (ServiceReceiver receiver : serviceReceivers) {
				users.add(receiver.getUser());
			}
		} else {// seeker

			travelServiceDao.saveServiceReceiver(travelId, userId);
			List<ServiceProvider> serviceProviders = travelServiceDao
					.loadServiceProviders(travelId);

			for (ServiceProvider provider : serviceProviders) {
				users.add(provider.getUser());
			}
		}

		model.addAttribute("users", users);
		System.out.println("---------USERS--------" + users.size());

		// Save user info
		// From travel id load results and show useremail,id in page
		return "results";
	}

	@RequestMapping(value = "register", method = RequestMethod.POST)
	public String register(String email, BindingResult result, Model model) {
		if (result.hasErrors()) {
			return null;
		}
		String nextView = "page3";

		String password = RandomStringUtils.randomAlphanumeric(8);
		MailUtil.sendRegistrationMail(email, password);
		try {
			travelServiceDao.createUser(email, password);
		} catch (UserExistsException e) {
			nextView = "register";
		}

		return nextView;
	}

	@InitBinder
	public void initBinder(WebDataBinder binder) {

		binder.registerCustomEditor(com.bloom.model.ServiceInfo.UserType.class,
				new EnumEditor(ServiceInfo.UserType.class));
		binder.registerCustomEditor(
				com.bloom.model.ServiceInfo.ServiceType.class, new EnumEditor(
						ServiceInfo.ServiceType.class));
	}

}
